package com.dogegg.lbbopenapi.security;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

public class Signature {

    private static final HashMap<String,Strategy> factory = new HashMap<>();

    public static final String RSA1 = "rsa1";
    public static final String RSA2 = "rsa2";
    public static final String SM2 = "sm2";


    static {
        factory.put(RSA1, new RSA1Signer());
        factory.put(RSA2, new RSA2Signer());
    }

    public static Strategy getSigner(String key){
        String type = key.toLowerCase();
        Strategy signer = factory.get(type);
        if(signer == null){
            throw new IllegalArgumentException("signType must [ras1,rsa2,md5]");
        }
        return signer;
    }

    public static String sign(String signType,Map<String,Object> map, String privateKey){

        String signContent = toSignContent(map);

        return getSigner(signType).sign(signContent,privateKey);

    }

    public static boolean verifySign(String signType,Map<String,Object> map,String sign, String publicKey){

        String signContent = toSignContent(map);

        return getSigner(signType).verify(signContent,publicKey,sign);

    }

    public static String toSignContent(Map<String,Object> map){
        return toSignContent(map,null);
    }

    public static String toSignContent(Map<String,Object> map, List<String> ignores ){
        StringBuilder toSign = new StringBuilder();
        if(map != null){
             for (String key : new TreeMap<>(map).keySet()) {
                 Object value = map.get(key);
                 if(value == null || (ignores !=null && ignores.contains(key))){
                     continue;
                 }
                 toSign.append(key).append("=").append(value).append("&");
             }
             if (toSign.length() >= 1) {
                 toSign.deleteCharAt(toSign.length() - 1);
             }
        }
        return toSign.toString();
    }


    interface Strategy {
        String sign(String content, String privateKey);
        boolean verify(String content, String publicKey, String sign);
    }

    static class RSA1Signer implements Strategy {
        @Override
        public String sign(String content, String privateKey) {
           throw new UnsupportedOperationException("RSA1 sign not supported");
        }
        @Override
        public boolean verify(String content, String publicKey, String sign) {
           throw new UnsupportedOperationException("RSA1 verify not supported");
        }
    }

    static class RSA2Signer implements Strategy {
        @Override
        public String sign(String content, String privateKey) {
           throw new UnsupportedOperationException("RSA2 sign not supported");
        }
        @Override
        public boolean verify(String content, String publicKey, String sign) {
           throw new UnsupportedOperationException("RSA2 verify not supported");
        }
    }
}
